/**
  ******************************************************************************
  * @file    MPU6050_Config.c
  * @brief   MPU6050六轴传感器(I2C接口)驱动实现
  * @author  18408107475@163.com
  * @version V1.0
  * @date    2025-7-15
  * @note    硬件特性：
  *          - 三轴加速度计(±2/±4/±8/±16g)
  *          - 三轴陀螺仪(±250/±500/±1000/±2000°/s)
  *          - 数字运动处理器(DMP)支持9轴融合
  *          - I2C接口(400kHz)，可选SPI(1MHz)
  *          - 内置温度传感器
  *          - 工作电压：2.375V-3.46V
  *
  * @attention 移植说明：
  *          1. 硬件连接：
  *             - SCL：PB6 (需4.7K上拉电阻)
  *             - SDA：PB7 (需4.7K上拉电阻)
  *             - AD0：接地(I2C地址0x68)或接VCC(地址0x69)
  *          2. 软件适配：
  *             - 修改IIC_GPIO_Config()中的端口定义
  *             - 调整Delay_ms()为实际平台的毫秒延时
  *             - 确保I2C通信速率≤400kHz
  ******************************************************************************
  */

#include "MPU6050_Config.h"

/**
  * @brief  I2C起始信号
  * @note   产生I2C总线起始条件：
  *         - SCL保持高电平时，SDA由高变低
  *         - 时序要求：SDA建立时间≥4.7μs
  */
void MPU6050_Start(void)
{
    IIC_Start();  // 调用底层I2C驱动（模拟SDA和SCL引脚操作）
}

/**
  * @brief  I2C停止信号
  * @note   产生I2C总线停止条件：
  *         - SCL保持高电平时，SDA由低变高
  *         - 时序要求：SDA建立时间≥4.7μs
  */
void MPU6050_Stop(void)
{
    IIC_Stop();   // 调用底层I2C驱动
}

/**
  * @brief  等待从机应答
  * @retval true: 收到ACK(从机拉低SDA), false: 无应答(通信失败)
  * @note   应答检测机制：
  *         1. 主机释放SDA线(置为输入)
  *         2. 发送一个SCL时钟脉冲
  *         3. 读取SDA电平：低=ACK，高=NACK
  */
bool MPU6050_Wait_ACK(void)
{
    return IIC_Wait_Ack();  // 检测SDA电平状态
}

/**
  * @brief  向MPU6050指定寄存器写入数据
  * @param  Reg_Address: 目标寄存器地址
  * @param  IIC_Data: 要写入的数据
  * @retval true: 写入成功, false: 写入失败
  * @note   I2C通信序列：
  *         1. 发送起始信号
  *         2. 发送设备地址(写模式)
  *         3. 发送寄存器地址
  *         4. 发送数据
  *         5. 发送停止信号
  */
bool MPU6050_Write_Data(u8 Reg_Address, u8 IIC_Data)
{
    // 调用底层I2C写函数：设备地址+寄存器地址+数据
    return IIC_Write_Data(MPU6050_SLAVE_ADDRESS, Reg_Address, IIC_Data);
}

/**
  * @brief  从MPU6050指定寄存器读取数据
  * @param  Reg_Address: 目标寄存器地址
  * @retval 寄存器中的数据
  * @note   I2C通信序列：
  *         1. 发送起始信号
  *         2. 发送设备地址(写模式)
  *         3. 发送寄存器地址
  *         4. 发送重复起始信号
  *         5. 发送设备地址(读模式)
  *         6. 读取数据
  *         7. 发送NACK和停止信号
  */
u8 MPU6050_Read_Data(u8 Reg_Address)
{
    // 调用底层I2C读函数：设备地址+寄存器地址→返回数据
    return IIC_Read_Data(MPU6050_SLAVE_ADDRESS, Reg_Address);
}

/**
  * @brief  MPU6050初始化配置
  * @note   配置流程：
  *         1. 复位并唤醒传感器
  *         2. 设置采样率和滤波器
  *         3. 配置加速度计和陀螺仪量程
  *         4. 禁用中断和FIFO
  */
void MPU6050_Config(void)
{
    IIC_Init();  // 初始化I2C总线

    Delay_ms(200);  // 等待传感器上电稳定

    // 配置电源管理寄存器
    MPU6050_Write_Data(PWR_MGMT_1, 0x01);  // 解除休眠，选择陀螺仪X轴作为时钟源
    MPU6050_Write_Data(PWR_MGMT_2, 0x00);  // 启用所有轴的加速度计和陀螺仪

    // 配置采样率和滤波器
    MPU6050_Write_Data(SMPLRT_DIV, 0x09);  // 采样率分频：1kHz/(9+1)=100Hz
    MPU6050_Write_Data(CONFIG, 0x06);      // 数字低通滤波器：带宽5Hz，延迟98ms

    // 配置陀螺仪量程(±2000°/s)
    MPU6050_Write_Data(GYRO_CONFIG, 0x18);  // FS_SEL=3 → ±2000°/s，灵敏度16.4 LSB/(°/s)

    // 配置加速度计量程(±16g)
    MPU6050_Write_Data(ACCEL_CONFIG, 0x18);  // AFS_SEL=3 → ±16g，灵敏度2048 LSB/g
}

/**
  * @brief  获取MPU6050设备ID
  * @retval 设备ID(WHO_AM_I寄存器值，正常为0x68)
  * @note   用于验证I2C通信是否正常
  */
u8 MPU6050_GetID(void)
{
    return MPU6050_Read_Data(WHO_AM_I);  // 读取设备ID寄存器
}

/**
  * @brief  读取MPU6050的六轴数据
  * @param  AccX,AccY,AccZ: 加速度计三轴原始数据指针
  * @param  GyroX,GyroY,GyroZ: 陀螺仪三轴原始数据指针
  * @note   数据格式：16位有符号整数，需根据量程转换为物理值
  *         例如：加速度值(g) = 原始值/灵敏度(2048 LSB/g for ±16g)
  */
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
                     int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
    u8 DataH, DataL;  // 高8位和低8位数据
    
    // 读取加速度计X轴数据
    DataH = MPU6050_Read_Data(ACCEL_XOUT_H);
    DataL = MPU6050_Read_Data(ACCEL_XOUT_L);
    *AccX = (DataH << 8) | DataL;  // 合并高低字节为16位值
    
    // 读取加速度计Y轴数据
    DataH = MPU6050_Read_Data(ACCEL_YOUT_H);
    DataL = MPU6050_Read_Data(ACCEL_YOUT_L);
    *AccY = (DataH << 8) | DataL;
    
    // 读取加速度计Z轴数据
    DataH = MPU6050_Read_Data(ACCEL_ZOUT_H);
    DataL = MPU6050_Read_Data(ACCEL_ZOUT_L);
    *AccZ = (DataH << 8) | DataL;
    
    // 读取陀螺仪X轴数据
    DataH = MPU6050_Read_Data(GYRO_XOUT_H);
    DataL = MPU6050_Read_Data(GYRO_XOUT_L);
    *GyroX = (DataH << 8) | DataL;
    
    // 读取陀螺仪Y轴数据
    DataH = MPU6050_Read_Data(GYRO_YOUT_H);
    DataL = MPU6050_Read_Data(GYRO_YOUT_L);
    *GyroY = (DataH << 8) | DataL;
    
    // 读取陀螺仪Z轴数据
    DataH = MPU6050_Read_Data(GYRO_ZOUT_H);
    DataL = MPU6050_Read_Data(GYRO_ZOUT_L);
    *GyroZ = (DataH << 8) | DataL;
}
